package mskruch.gps.calculation;

import gpstools.TrainingPoint;

import java.util.LinkedList;
import java.util.List;

import mskruch.gps.Point;
import mskruch.gps.PointFactory;

public class DefaultElevationCalculator implements ElevationCalculator {
    private static final int DEFAULT_WINDOW_SIZE = 48;

    int windowSize = DEFAULT_WINDOW_SIZE;

    /** most recent added point */
    private Point last = null;

    private double elevationGain = 0;
    private double elevationLoss = 0;

    private List<Double> history = new LinkedList<Double>();

    private long startTime;
    private int storedSeconds;
    private double current;

    DefaultElevationCalculator() {
    }

    /* (non-Javadoc)
     * @see mskruch.gps.calculation.ElevationCalculator#add(mskruch.gps.Point)
     */
    @Override
    public ElevationCalculator add(Point point) {
        /* can be more efficent */
        if (last != null) {
            long time = point.getTime() - startTime;
            int seconds = (int) (time / 1000);
            seconds -= storedSeconds;
            for (int i = 0; i < seconds; i++) {
                history.add(point.getElevation());
                storedSeconds++;
            }

            while (history.size() > getWindowSize()) {
                history.remove(0);
            }
            
            double next = point.getElevation();

            if (!history.isEmpty()) {
                double sum = 0;
                for (Double value : history) {
                    sum += value;
                }
                next = sum / history.size();
            }

            if (next > current) {
                elevationGain += next - current;
            } else {
                elevationLoss += current - next;
            }

            current = next;
        } else {
            startTime = point.getTime();
            current = point.getElevation();
        }
        last = point;
        return this;
    }
    
    @Override
    public void add(TrainingPoint point) {
        add(PointFactory.newPoint(point));
    }

    private int getWindowSize() {
        return windowSize;
    }

    /* (non-Javadoc)
     * @see mskruch.gps.calculation.ElevationCalculator#getElevationLoss()
     */
    @Override
    public double getElevationLoss() {
        return elevationLoss;
    }

    /* (non-Javadoc)
     * @see mskruch.gps.calculation.ElevationCalculator#getElevationGain()
     */
    @Override
    public double getElevationGain() {
        return elevationGain;
    }

    /* (non-Javadoc)
     * @see mskruch.gps.calculation.ElevationCalculator#getCurrent()
     */
    @Override
    public Double getCurrent() {
        if (last == null) {
            return null;
        } else
            return current;
    }

}
